package com.currentcms.client.component;

import java.util.ArrayList;
import java.util.List;

import com.allen_sauer.gwt.dnd.client.PickupDragController;
import com.allen_sauer.gwt.dnd.client.drop.FlowPanelDropController;
import com.currentcms.client.ICellRenderer;
import com.currentcms.client.IEditor;
import com.currentcms.client.StyleNames;
import com.currentcms.client.dialog.ConfirmDialog;
import com.currentcms.client.event.ChangeValueEvent;
import com.currentcms.client.event.ChangeValueHandler;
import com.currentcms.client.event.ConfirmEvent;
import com.currentcms.client.event.ConfirmHandler;
import com.currentcms.client.event.DeleteEvent;
import com.currentcms.client.event.DeleteHandler;
import com.currentcms.client.event.SelectEvent;
import com.currentcms.client.event.SelectHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.WidgetCollection;

public class ListEditor<T> extends FlowPanel implements IEditor<List<T>>
{
    private final HandlerManager handlerManager = new HandlerManager(this);

    private boolean reorderable;

    private boolean deletable;

    private boolean deleteConfirm;

    private boolean dirty;

    private PickupDragController dragController;

    private FlowPanelDropController dropController;

    private ICellRenderer<T> cellRenderer;

    private WidgetMap wmap = new WidgetMap();

    public ListEditor(boolean reorderable, boolean deletable, boolean confirmDelete)
    {
        this.reorderable = reorderable;
        this.deletable = deletable;
        this.deleteConfirm = confirmDelete;
        this.dirty = false;

        setStyleName(StyleNames.CLASS_LIST_EDITOR);

        if(reorderable)
        {
            dropController = new FlowPanelDropController(this);
            // i hate to pass it around from the entry point....so...here is a static reference
            dragController = new PickupDragController(RootPanel.get(StyleNames.ID_CONTENT_CENTER), false);
            dragController.setBehaviorDragStartSensitivity(4);
            dragController.registerDropController(dropController);
        }

        setCellRenderer(new ICellRenderer<T>()
        {
            public Widget createWidget(T o)
            {
                return new Label(o.toString());
            }
        });
    }

    public void setCellRenderer(ICellRenderer<T> cell_renderer)
    {
        cellRenderer = cell_renderer;
    }

    public void setValue(List<T> o)
    {
        dirty = false;
        wmap.clear();
        clear();
        int s = o.size();
        for(int i = 0; i < s; i++)
            add(create_widget(o.get(i)));
    }

    public List<T> getValue()
    {
        List<T> v = new ArrayList<T>();
        WidgetCollection c = getChildren();
        int s = c.size();
        for(int i = 0; i < s; i++)
        {
            @SuppressWarnings("unchecked")
            ListItem<T> l = (ListItem<T>)c.get(i);
            v.add(l.getValue());
        }
        return v;
    }

    public boolean getDirty()
    {
        return dirty;
    }

    public void setDirty(boolean dirty)
    {
        this.dirty = dirty;
    }

    public Widget addValue(T o)
    {
        Widget w = create_widget(o);
        add(w);
        return w;
    }

    public void removeValue(T o)
    {
        Widget w = wmap.get(o);
        if(w != null)
        {
            remove(w);
            wmap.remove(o);
        }
    }

    private Widget create_widget(final T o)
    {
        Widget w = cellRenderer.createWidget(o);
        final ListItem<T> listItem = new ListItem<T>(deletable);
        listItem.addSelectHandler(new SelectHandler<T>()
        {
            @Override
            public void onSelectEvent(SelectEvent<T> event)
            {
                select_item(listItem, o);
            }
        });
        listItem.addDeleteHandler(new DeleteHandler()
        {
            @Override
            public void onDeleteEvent(DeleteEvent event)
            {
                delete_item(listItem, o);
            }
        });
        listItem.setWidget(w);
        listItem.setValue(o);
        wmap.put(o, listItem);

        if(reorderable)
            dragController.makeDraggable(listItem);
        return listItem;
    }

    protected void delete_item(final ListItem<T> w, T o)
    {
        if(deleteConfirm)
        {
            ConfirmDialog d = new ConfirmDialog();
            d.setMessage("Are you sure you want to delete this?");
            d.addConfirmHandler(new ConfirmHandler()
            {
                @Override
                public void onConfirmEvent(ConfirmEvent event)
                {
                    delete_item(w);
                }
            });
            d.setRelativePosition(w.getDeleteButton());
            d.show();
        }
        else
        {
            delete_item(w);
        }
    }

    private void delete_item(Widget w)
    {
        dirty = true;
        remove(w);
        handlerManager.fireEvent(new ChangeValueEvent(this, getValue()));
    }

    protected void select_item(Widget w, T o)
    {
        System.out.println(">EDIT " + o + " " + w);
        // TODO dispatch
    }

    public int size()
    {
        return getChildren().size();
    }

    @Override
    public HandlerRegistration addChangeValueHandler(ChangeValueHandler handler)
    {
        return handlerManager.addHandler(ChangeValueEvent.getType(), handler);
    }

}
